package com.iss.umservice.common.xml;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
 * <p>
 * [���ܼ���] xml�ڵ㴦�����
 * <p>
 * <p>
 * [��ϸ����] ��Dom��ʽ����XML,�ṩxpath����
 * </p>
 * @author  gcxu
 * @version  [GZT 1.00, Sep 7, 2010]
 * @see  [�����/����]
 * @since  [GZT]
 */
public class XmlDomNode
{
    /** �ĵ����� */
    private Document document = null;
    
    /**
     * Ĭ�Ϲ��캯��
     */
    public XmlDomNode()
    {
    }
    
    /**
     * Ĭ�Ϲ��캯��
     */
    public XmlDomNode(Document document)
    {
        this.document = document;
    }
    
    /**
     * @return ���� document
     */
    public Document getDocument()
    {
        return document;
    }
    
    /**
     * @param ��document���и�ֵ
     */
    public void setDocument(Document document)
    {
        this.document = document;
    }
    
    /**  
     * �>ݽڵ���Ʋ��Ҹýڵ�������ı��ڵ��ֵ����(�ýڵ���ӽڵ㣩  
     * @param nodeName   �ڵ����
     * @return  List<String> 
     */
    public List<String> getNodeValue(String nodeName)
    {
        if (null == document || null == nodeName || "".equals(nodeName))
        {
            return new ArrayList<String>(0);
        }
        
        ArrayList<String> values = new ArrayList<String>();
        NodeList nl = document.getElementsByTagName(nodeName);
        int length = nl.getLength();
        for (int i = 0; i < length; i++)
        {
            Node node = nl.item(i);
            if (node.getNodeType() == Node.TEXT_NODE)
            {
                String value = node.getNodeValue();
                if (!(value.trim().equals("")))
                {
                    values.add(value);
                }
            }
            else if (node.getNodeType() == Node.ELEMENT_NODE)
            {
                traversalNode(node, values);
            }
        }
        return values;
    }
    
    /**  
     * �ݹ���ҵ�ǰ�ڵ�������ı��ڵ�  
     * @param node  
     * @param values  
     */
    private void traversalNode(Node node, ArrayList<String> values)
    {
        if (node == null)
        {
            return;
        }
        NodeList nl = node.getChildNodes();
        int length = nl.getLength();
        for (int i = 0; i < length; i++)
        {
            Node n = nl.item(i);
            if (n.getNodeType() == Node.TEXT_NODE)
            {
                String value = n.getNodeValue();
                if (!(value.trim().equals("")))
                {
                    values.add(value);
                }
            }
            else if (n.getNodeType() == Node.ELEMENT_NODE)
            {
                traversalNode(n, values);
            }
        }
    }
    
    /**  
     *  �>ݵ�ǰԪ����ƣ����Ҹ�Ԫ�ص���������  
     * @param nodeName  �ڵ����
     * @return  Map<String, String>
     */
    public Map<String, String> getNodeAttributes(String nodeName)
            throws Exception
    {
        if (null == document || null == nodeName || "".equals(nodeName))
        {
            return new HashMap<String, String>(0);
        }
        Map<String, String> map = new HashMap<String, String>();
        NodeList nl = document.getElementsByTagName(nodeName);
        int length = nl.getLength();
        for (int i = 0; i < length; i++)
        {
            Node node = nl.item(i);
            if (node.getNodeType() != Node.ELEMENT_NODE)
            {
                throw new Exception();
            }
            else
            {
                NamedNodeMap attrs = node.getAttributes();
                int len = attrs.getLength();
                for (int j = 0; j < len; j++)
                {
                    Node attr = attrs.item(j);
                    map.put(attr.getNodeName(), attr.getNodeValue());
                }
            }
        }
        return map;
    }
    
    /**  
     * �>�ָ����������xml�ĵ�  
     * @param out  �����
     * @throws Exception  
     */
    public void transformer(OutputStream out) throws Exception
    {
        if (null == document)
        {
            return;
        }
        
        TransformerFactory tff = TransformerFactory.newInstance();
        Transformer tf = tff.newTransformer();
        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(out);
        tf.transform(source, result);
    }
    
    /**
     * 
     * <p>
     * [���ܼ���] ��ȡ�ƶ��ڵ��NodeList�б�
     * <p>
     * <p>
     * [��ϸ����] ��ȡ�ƶ��ڵ��NodeList�б�
     * </p>
     * @param xpathExpress xPath���ʽ
     * @return Node
     * @exception throws [Υ������] [Υ��˵��]
     * @see [�ࡢ��#��������#��Ա]
     */
    public Node getNode(String xpathExpress)
    {
        if (null == document)
        {
            return null;
        }
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = null;
        
        try
        {
            expr = xpath.compile(xpathExpress);
        }
        catch (XPathExpressionException e)
        {
            return null;
        }
        Node node = null;
        try
        {
            node = (Node)expr.evaluate(document, XPathConstants.NODE);
        }
        catch (XPathExpressionException e)
        {
            return null;
        }
        
        return node;
    }
    
    /**
     * 
     * <p>
     * [���ܼ���] ��ȡ�ƶ��ڵ��NodeList�б�
     * <p>
     * <p>
     * [��ϸ����] ��ȡ�ƶ��ڵ��NodeList�б�
     * </p>
     * @param xpathExpress xPath���ʽ
     * @return NodeList
     * @exception throws [Υ������] [Υ��˵��]
     * @see [�ࡢ��#��������#��Ա]
     */
    public NodeList getNodeList(String xpathExpress)
    {
        if (null == document)
        {
            return null;
        }
        
        NodeList nodeList = null;
        
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = null;
        
        try
        {
            expr = xpath.compile(xpathExpress);
        }
        catch (XPathExpressionException e)
        {
            return null;
        }
        
        try
        {
            nodeList = (NodeList)expr.evaluate(document, XPathConstants.NODESET);
        }
        catch (XPathExpressionException e)
        {
            return null;
        }
        
        return nodeList;
    }
    
    /**
     * 
     * <p>
     * [���ܼ���] ���xPath���ʽ�����ƶ��ڵ��ı�
     * <p>
     * <p>
     * [��ϸ����] ���xPath���ʽ�����ƶ��ڵ��ı�
     * </p>
     * @param xpathExpress xpath���ʽ
     * @return String 
     * @exception throws [Υ������] [Υ��˵��]
     * @see [�ࡢ��#��������#��Ա]
     */
    public String getNodeText(String xpathExpress)
    {
        if (null == document)
        {
            return "";
        }
        
        String result = null;
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = null;
        
        try
        {
            expr = xpath.compile(xpathExpress);
        }
        catch (XPathExpressionException e)
        {
            return "";
        }
        
        try
        {
            result = (String)expr.evaluate(document, XPathConstants.STRING);
        }
        catch (XPathExpressionException e)
        {
            return "";
        }
        
        return result;
    }

    /**  
     * ��ӡxml�ĵ������нڵ�  
     * @param node  �ڵ�
     * @param sb  StringBuffer
     */
    private void printerNode(Node node, StringBuffer sb)
    {
        if (null == node)
        {
            return;
        }
        NodeList nl = node.getChildNodes();
        for (int i = 0; i < (nl.getLength()); i++)
        {
            Node n = nl.item(i);
            if (n.getNodeType() == Node.ELEMENT_NODE)
            {
                String nodeName = n.getNodeName();
                sb.append("<");
                sb.append(null == n.getNodeName() ? "" : n.getNodeName().trim());
                printerAttributesNode(n, sb);
                sb.append(">");
                printerNode(n, sb);
                sb.append("</");
                sb.append(null == nodeName ? "" : nodeName.trim());
                sb.append(">\n");
            }
            else if (n.getNodeType() == Node.TEXT_NODE)
            {
                printerTextNodeInfo(n, sb);
            }
            else if (n.getNodeType() == Node.COMMENT_NODE)
            {
                sb.append("<!--");
                printerTextNodeInfo(n, sb);
                sb.append("-->\n");
            }
            else
            {
                printerTextNodeInfo(n, sb);
            }
            
        }
    }
    
    /**  
     * ��ӡ�ı��ڵ�����  
     * @param node  �ڵ�
     */
    private void printerTextNodeInfo(Node node, StringBuffer sb)
    {
        if (null == node)
        {
            return;
        }
        
        String value = node.getNodeValue();
        if (null == value)
        {
            return;
        }
        
        if (!(value.trim().equals("")))
        {
            //��ȥ�հ׵��ı��ڵ�   
            sb.append(value.trim());
        }
    }
    
    /**  
     * ��ӡ���Խڵ���ƺ�ֵ  
     * @param node  �ڵ����
     */
    private void printerAttributesNode(Node node, StringBuffer sb)
    {
        if (null == node)
        {
            return;
        }
        NamedNodeMap attrs = node.getAttributes();
        int length = attrs.getLength();
        for (int i = 0; i < length; i++)
        {
            Node attr = attrs.item(i);
            sb.append(" ");
            sb.append(null == attr.getNodeName() ? "" : attr.getNodeName()
                    .trim());
            sb.append("=\"");
            sb.append(null == attr.getNodeValue() ? "" : attr.getNodeValue()
                    .trim());
            sb.append("\"");
        }
    }
}